package com.dzsw.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    @Primary
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory,
                                     StringRedisSerializer keySerializer,
                                     Jackson2JsonRedisSerializer valueSerializer) {
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(factory)
                .cacheDefaults(getRedisCacheConfigWithTtl(keySerializer, valueSerializer, -1))
                .transactionAware()
                .withInitialCacheConfigurations(getRedisCacheConfigMap(keySerializer, valueSerializer));
        return builder.build();
    }

    @Override
    public KeyGenerator keyGenerator() {
        return (o, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(o.getClass().getName()).append(".");
            sb.append(method.getName()).append(".");
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
//            System.out.println("keyGenerator=" + sb.toString());
            return sb.toString();
        };
    }

    @Bean
    public CacheResolver cacheResolver(CacheManager cacheManager) {
        return new SimpleCacheResolver(cacheManager);
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return new SimpleCacheErrorHandler();
    }

    /**
     * Description : 指定value策略，只要注解的value（cacheName）设置的是这里面的值，就会使用这种策略
     *
     * @param
     * @return 指定value的策略集合
     */
    private Map<String, RedisCacheConfiguration> getRedisCacheConfigMap(StringRedisSerializer ks, Jackson2JsonRedisSerializer vs) {
        Map<String, RedisCacheConfiguration> map = new HashMap<>();
        // 有效时间1分钟
        map.put("c_1", this.getRedisCacheConfigWithTtl(ks, vs, 60));
        // 有效时间2分钟
        map.put("c_2", this.getRedisCacheConfigWithTtl(ks, vs, 2 * 60));
        // 有效时间3分钟
        map.put("c_3", this.getRedisCacheConfigWithTtl(ks, vs, 3 * 60));
        // 有效时间3分钟
        map.put("c_10", this.getRedisCacheConfigWithTtl(ks, vs, 10 * 60));
        // 有效时间30分钟
        map.put("c_30", this.getRedisCacheConfigWithTtl(ks, vs, 30 * 60));
        // 有效时间120分钟，7200秒
        map.put("c_120", this.getRedisCacheConfigWithTtl(ks, vs, 120 * 60));
        return map;
    }

    /**
     * Description :设置Redis缓冲配置以及配置redis有效时间
     *
     * @param seconds 数据有效时间
     * @return
     */
    private RedisCacheConfiguration getRedisCacheConfigWithTtl(StringRedisSerializer ks,
                                                               Jackson2JsonRedisSerializer vs,
                                                               Integer seconds) {
        return RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(ks))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(vs))
                .entryTtl(Duration.ofSeconds(seconds))
                .disableKeyPrefix()          //禁止该缓冲使用redis前缀
                .disableCachingNullValues(); //禁止对null值进行缓冲
    }

}
